package com.cj.review;

import com.cj.Dialect;
import com.cj.MysqlDialect;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.Map;
import java.util.Properties;

/**
 * 自定义插件 修改插件参数
 * @author cc
 * @date 2025-05-23 16:50
 **/
@Intercepts({
        @Signature(type= Executor.class,method = "query",args={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class PageInterceptor implements Interceptor {

    private Dialect dialect = new MysqlDialect();


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();


        // 映射配置文件中 定义的SQL节点
        MappedStatement ms = (MappedStatement) args[0];

        // 用户传入的实际参数
        Object parameterObject = args[1];


        // mybatis默认的分页对象
        RowBounds rowBounds = (RowBounds) args[2];

        // 不需要分页就直接放行
        if (rowBounds == RowBounds.DEFAULT) {
            return invocation.proceed();
        }

        int offset = rowBounds.getOffset();
        int limit = rowBounds.getLimit();


        // 带？占位符的sql  +  参数配置
        BoundSql boundSql = ms.getBoundSql(parameterObject);

        String sql = boundSql.getSql();

        // 带分页的sql语句
        String pagingSql = dialect.getPagingSql(sql, offset, limit);


        // 如果使用pagingSql直接执行，，那么之前的RowBounds控制的查找结果集就不要再控制了，，，将它置为默认的RowBounds
        args[2] = RowBounds.DEFAULT;


        // 创建了新的BoundSql

        MappedStatement newMappedStatement = createMappedStatement(ms, boundSql, pagingSql);

        args[0] = newMappedStatement;


        // 拦截的是Executor.query()方法
        return invocation.proceed();
    }


    private BoundSql createNewBoundSql(MappedStatement ms,BoundSql boundSql,String sql){
        return new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
    }

    private MappedStatement createMappedStatement(MappedStatement ms,BoundSql boundSql,String sql){
        BoundSql newBoundSql = createNewBoundSql(ms, boundSql, sql);
        // 创建新的MappedStatement对象

        return createMappedStatement(ms,newBoundSql);

    }

    /**
     *
     * @param ms 原来的ms
     * @param boundSql 新的BoundSql
     * @return
     */
    private MappedStatement createMappedStatement(MappedStatement ms,BoundSql boundSql){
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId() + "_Page", new SqlSource() {
            @Override
            public BoundSql getBoundSql(Object parameterObject) {
                return boundSql;
            }
        }, ms.getSqlCommandType());


        // 复制原属性配置
        return builder.resource(ms.getResource())
                .fetchSize(ms.getFetchSize())
                .statementType(ms.getStatementType())
                .keyGenerator(ms.getKeyGenerator())
                .timeout(ms.getTimeout())
                .parameterMap(ms.getParameterMap())
                .resultMaps(ms.getResultMaps())
                .cache(ms.getCache())
                .build();

    }


    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        String dbName = properties.getProperty("dbName");
        Interceptor.super.setProperties(properties);
    }
}
